//--------------------------------------------------------------------------------------//
//                                                                                      //
//    __  __  __    __    __  ___   __   ___  __    ___    __  __  __  ___  ___  __     //
//   / _)/  \(  )  (  )  (  )(   \ (  ) (  ,)(  )  (  _)  (  \/  )/  \(   \(  _)(  )    //
//  ( (_( () ))(__  )(__  )(  ) ) )/__\  ) ,\ )(__  ) _)   )    (( () )) ) )) _) )(__   //
//   \__)\__/(____)(____)(__)(___/(_)(_)(___/(____)(___)  (_/\/\_)\__/(___/(___)(____)  //
//                                                                                      //
//                                                                                      //
//       Copyright by Theodor Mader, 2009                                               //
//			www.theomader.com/public/Projects.html                                      //
//--------------------------------------------------------------------------------------//

#ifndef __THREADING_H_INCLUDED__
#define __THREADING_H_INCLUDED__

#include <Windows.h>
#include <vector>
#include <list>

#include "geometry.h"

// if DEPTH_FIRST_PROCESSING is defined, the tree is built in depth first order. 
// if DEPTH_FIRST_PROCESSING is not defined, it will be created in breadth first order.
#define DEPTH_FIRST_PROCESSING 

struct BspNode;
class BspTree;

namespace Threading
{

	class Scheduler;

	struct Task 
	{
		BspNode*& node;
		std::vector<unsigned int> indices;

		Task( BspNode*& n ) : node( n ) {}
	};

	struct TaskData
	{
		Scheduler& scheduler;
		TaskData( Scheduler& s ) : scheduler( s ) {}
	};

	class Scheduler
	{
		std::list<Task*> m_TaskList;
		volatile long m_iNumWaitingThreads;
		unsigned int m_iNumThreads;
		unsigned int m_iNumVerticesPerLeaf;

		CRITICAL_SECTION m_CriticalSection;

		const std::vector<Geometry::Vertex>& m_Vertices;

	public:
		Scheduler( const std::vector<Geometry::Vertex>& vertices, unsigned int numVerticesPerLeaf, unsigned int numThreads );
		~Scheduler();

		void AddTask( Task* task );
		void AddTasks( const std::list<Task*>& task );
		Task* TryGetTask();

		void IncreaseNumWaitingThreads();
		void DecreaseNumWaitingThreads();

		inline const std::vector<Geometry::Vertex>& GetVertices() { return m_Vertices; }
		inline unsigned int NumVerticesPerLeaf() { return m_iNumVerticesPerLeaf; }

		void StartProcessing();

		HANDLE NewTasksAvailableEvent;
		HANDLE AllTasksFinishedEvent;
	};

	DWORD __stdcall ProcessTasksWorker( LPVOID taskData );	
}

#endif